package netty.bio;

import cn.hutool.core.date.DateUtil;
import lombok.extern.slf4j.Slf4j;
import org.junit.Test;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Date;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * @program NettyLeaning
 * @description: 伪异步 同步阻塞式IO处理 一请求一线程，线程池处理
 *  - 弊端
 *      - InputStream.read()方法，不阻塞的条件：有数据可读、数据读取完毕、异常
 *        若发送方的数据由于网络问题很满，那么线程总是阻塞在read方法里，耗尽线程池，存在问题
 *      - 同理，OutputStream.write也存在阻塞问题
 * @author: zhanglu
 * @create: 2022-01-16 18:48:00
 */
@Slf4j
public class TimeServerClient2 {

    private static final String IP = "127.0.0.1";
    private static final Integer PORT = 8080;
    private ExecutorService executor = new ThreadPoolExecutor(Runtime.getRuntime().availableProcessors(),
            Runtime.getRuntime().availableProcessors(), 60L, TimeUnit.SECONDS, new LinkedBlockingQueue<>(100));

    @Test
    public void server() throws Exception {
        ServerSocket server = null;
        try {
            server = new ServerSocket(PORT);
            log.info("time server start port. " + PORT);
            Socket socket = null;
            while (true){
                socket = server.accept();
                Socket handlerSocket = socket;
                executor.execute(() -> {
                   BufferedReader in = null;
                   PrintWriter out = null;
                   try {
                       in = new BufferedReader(new InputStreamReader(handlerSocket.getInputStream()));
                       out = new PrintWriter(handlerSocket.getOutputStream(), true);
                       String currentTime = null;
                       String body = null;
                       while (true){
                           body = in.readLine();
                           if(body == null){
                               break;
                           }
                           log.info("server receive : " + body);
                           currentTime = DateUtil.formatDateTime(new Date());
                           out.println("server return : " + currentTime);
                       }
                   } catch (Exception e) {
                       e.printStackTrace();
                   } finally {
                       if(in != null){
                           try {
                               in.close();
                           } catch (IOException e) {
                               e.printStackTrace();
                           }
                       }
                       if(out != null){
                           out.close();
                       }
                       if(handlerSocket != null){
                           try {
                               handlerSocket.close();
                           } catch (IOException e) {
                               e.printStackTrace();
                           }
                       }
                   }
               });
            }
        }finally {
            if(server != null){
                log.info("server close");
                server.close();
            }
        }
    }

    @Test
    public void client() throws Exception{
        Socket socket = null;
        BufferedReader in = null;
        PrintWriter out = null;
        try {
            socket = new Socket(IP, PORT);
            in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
            out = new PrintWriter(socket.getOutputStream(), true);
            out.println("hello server");
            String res = in.readLine();
            log.info(res);
        } finally {
            if(in != null){
                try {
                    in.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if(out != null){
                out.close();
            }
            if(socket != null){
                try {
                    socket.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

}
